﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace KZ400B
{
    public partial class AxleManager
    {
        private static Thread s_tRecv = null;
        private static Thread s_tMsgProc = null;
        private static Queue<MsgItem> s_recvMsgQueue = new Queue<MsgItem>();
        private static object s_msgLocker = new object();
        private static MsgItem s_n_msg = null;

        private static long createMsgId()
        {
            DateTime nT = DateTime.Now;
            return nT.Ticks * 1000 + nT.Millisecond;
        }

        static void doRecv()
        {
            bool rFlg = isCommRunning();
            while (rFlg)
            {
                rFlg = isCommRunning();

                string nrdString = string.Empty;
                lock (s_spLocker) //链路锁
                {
                    if (spLink != null)
                    {
                        try
                        {
                            nrdString = spLink.ReadString(true);
                        }
                        catch (Exception ex)
                        {
                            if (OnAxleActionResponse != null)
                            {
                                OnAxleActionResponse(
                                    Axle.AllAxleName
                                    , new Axle(Axle.AllAxleName)
                                    , AxleActions.Failed
                                    , false
                                    , string.Format("数据接收失败:{0}", ex.Message)
                                    );
                            }
                        }
                    }
                    else
                    {
                        break;
                    }
                }
                if (string.IsNullOrEmpty(nrdString))
                {
                    Thread.Sleep(200);
                    continue;
                }
                else
                {
                    Int64 id = createMsgId();
                    addRecvMsg(id, nrdString);
                }
            }
        }

        private static void addRecvMsg(Int64 id, string msg)
        {
            int rcnt = 0;
            bool isFull = false;
            lock (s_msgLocker)
            {
                rcnt = s_recvMsgQueue.Count;
                if (!string.IsNullOrEmpty(msg))
                {
                    if(rcnt >= 10000)
                    {
                        s_recvMsgQueue.Clear();
                        isFull = true; 
                    }
                    s_recvMsgQueue.Enqueue(new MsgItem(id, msg));
                }
            }
            if (isFull)
            {
                Utility.FileOperate.WriteToLog("Auto Recv Msg Queue is Full.....");
            }

            //Process(new MsgItem(id,msg));
        }

        static void procMsg()
        {
            while (isCommRunning())
            {
                MsgItem msg = null;
                lock (s_msgLocker)
                {
                    if (s_recvMsgQueue != null && s_recvMsgQueue.Count > 0)
                    {
                        msg = s_recvMsgQueue.Dequeue();
                    }
                    else
                    {
                        Thread.Sleep(200);
                        continue;
                    }
                }
                if (msg != null)
                {
                    try
                    {
                        Process(msg);
                    }
                    catch (Exception ex)
                    {
                        if (OnAxleActionResponse != null)
                        {
                            OnAxleActionResponse(Axle.AllAxleName
                                    , AxleCacheManager.getAxle(Axle.AllAxleName)
                                , AxleActions.Exception
                                , false
                                , string.Format("处理 收到数据 发生错误：{0} "
                                , ex.Message
                                )
                            );
                        }
                    }
                }
                
            }
        }


        /// <summary>
        /// 调用时需要加锁 lock (s_msgLocker)
        /// </summary>
        /// <returns></returns>
        private static MsgItem getNewMsg()
        {

            MsgItem nMsg = null;
            //lock (s_msgLocker)
            {
                if (s_n_msg != null)
                {
                    nMsg = s_n_msg;
                }
                else if (s_recvMsgQueue.Count > 0)
                {
                    nMsg = s_recvMsgQueue.Dequeue();
                }
            }
            return nMsg;
        }

        /// <summary>
        /// 调用时需要加锁 lock (s_msgLocker)
        /// </summary>
        /// <param name="id"></param>
        private static void rmMsg(Int64 id)
        {
            //lock (s_msgLocker)
            {
                s_n_msg = null;
            }
        }

        static Dictionary<string, string> m_RepStringDict = new Dictionary<string, string>();
        static object m_lkRepDict = new object();
        static void addToRep(FunctionCode fc, string aName, string repString)
        {
            string kn = ProtocolV2.ResponseManager.getKeyName(fc, aName, true);
            lock (m_lkRepDict)
            {
                if (!m_RepStringDict.ContainsKey(kn))
                {
                    m_RepStringDict.Add(kn, repString);
                }
            }
        }

        static void rmRep(FunctionCode fc, string aName)
        {
            string kn = ProtocolV2.ResponseManager.getKeyName(fc, aName, true);
            lock (m_lkRepDict)
            {
                if (m_RepStringDict.ContainsKey(kn))
                {
                    m_RepStringDict.Remove(kn);
                }
            }
        }

        static string getMsgFromRepDic(FunctionCode fc, string aName)
        {
            string kn = ProtocolV2.ResponseManager.getKeyName(fc, aName, true);
            lock (m_lkRepDict)
            {
                if (m_RepStringDict.ContainsKey(kn))
                {
                    //m_RepStringDict.Remove(kn);
                    return m_RepStringDict[kn];
                }
            }
            return string.Empty;
        }
        
        public static CommResultCode normalSingleResponse(FunctionCode fc, string aName, string repString, object otherInfo)
        {
            CommResultCode rst = CommResultCode.UnkownError;

            string rp = getMsgFromRepDic(fc, aName);
            if (string.IsNullOrEmpty(rp))
            {
                rp = repString;
            }
            else
            {
                rmRep(fc,aName);
            }

            ProtocolV2.UnpacketResult ur = ProtocolV2.Unpack(rp);
           
            if( ur.Action == AxleActions.WrongFormat)
            {
                return CommResultCode.WrongFormat;
            }
            if (ur.Result)
            {
                if (ur.FunctionCode != fc.ToString())
                {
                    rst = CommResultCode.Exceptions;
                    addToRep(ur.FunctionCodeObject, ur.AxleName, rp);
                    return rst;
                }

                if (fc.FCode != CommFunctionCode.Contact)
                {
                    if (string.IsNullOrEmpty(aName) || ur.AxleName != aName)
                    {
                        rst = CommResultCode.WrongAxle;
                        if (ur.AxleName != aName)
                        {
                            addToRep(ur.FunctionCodeObject, ur.AxleName,rp);
                        }
                        return rst;
                    }
                }
                rst = CommResultCode.Success;
            }
            else
            {
                rst = CommResultCode.Failed;
            }
            
            return rst;

            //CommResultCode rst = CommResultCode.UnkownError;
            //if (!string.IsNullOrEmpty(repString))
            //{
            //    string oStr = repString;
            //    string tmpString = repString.TrimEnd(' ');

            //    string okString = ProtocolV2.ResponseManager.getResonseCode(fc, aName, true,otherInfo);//Protocol.getACKString();
            //    string errString = ProtocolV2.ResponseManager.getResonseCode(fc, aName, false, otherInfo);//Protocol.getNACKString();
            //    string wrongFormat = ProtocolV2.ResponseManager.getResonseCode(fc, aName);
            //    string nStr = string.Empty;
            //    if (tmpString.StartsWith(okString) || tmpString.EndsWith((okString+CommFlag.AllEnd) ))
            //    {
            //        rst = CommResultCode.Success;
            //        nStr = oStr.Replace(okString, string.Empty);
            //    }
            //    else if (tmpString.StartsWith(errString) || tmpString.EndsWith(errString+CommFlag.AllEnd))
            //    {
            //        rst = CommResultCode.Failed;
            //        //todo:error happen
            //        nStr = oStr.Replace(errString, string.Empty);
            //    }
            //    else if (wrongFormat.StartsWith(errString) || tmpString.EndsWith(wrongFormat + CommFlag.AllEnd))
            //    {
            //        rst = CommResultCode.WrongFormat;
            //        nStr = oStr.Replace(wrongFormat, string.Empty);
            //        Utility.FileOperate.WriteToLog("normalSingleResponse WrongFormat");
            //    }
            //    else
            //    {
            //        throw new nUnCompatibleFrameException();
            //    }
            //    if (!string.IsNullOrEmpty(nStr) && !string.IsNullOrEmpty(nStr.TrimEnd(' ')) )
            //    {
            //        long id = createMsgId();
            //        addRecvMsg(id,nStr);
            //        Utility.FileOperate.WriteToLog(string.Format("addRecvMsg in normalSingleResponse:{0}", nStr));
            //    }
            //}
            //return rst;
        }


        static CommResultCode handleNrmAck(FunctionCode fc, string aName, string msg, object otherInfo)
        {
            return handleNrmAck(fc,aName,msg,true,otherInfo);
        }

        static CommResultCode handleNrmAck(FunctionCode fc, string msg, object otherInfo)
        {
            return handleNrmAck(fc, string.Empty, msg, true, otherInfo);
        }

        static CommResultCode handleNrmAck(FunctionCode fc, string aName, string msg)
        {
            return handleNrmAck(fc, aName, msg, true, null);
        }

        static CommResultCode handleNrmAck(FunctionCode fc, string msg)
        {
            return handleNrmAck(fc, string.Empty,msg, true,null);
        }

        static CommResultCode handleNrmAck(FunctionCode fc, string aName, string msg, bool lockLink)
        {
            return handleNrmAck(fc,aName,msg,lockLink,null);
        }

        /// <summary>
        /// 处理普通响应帧
        /// </summary>
        /// <returns></returns>
        static CommResultCode handleNrmAck(FunctionCode fc, string aName, string msg, bool lockLink, object otherInfo)
        {
            bool ack = false;
            CommResultCode rst = CommResultCode.UnkownError;
            //bool commError = false;
            int counter = 0;

            List<MsgItem> otherMsgList = new List<MsgItem>();
            
            if (!string.IsNullOrEmpty(msg))
            {
                try
                {
                    rst = normalSingleResponse(fc,aName,msg,otherInfo);

                    //if (rst)
                    //{
                        return rst;
                    //}
                }
                catch (nUnCompatibleFrameException cfe)
                {
                    Utility.FileOperate.WriteToLog(cfe.Message);
                    //可能是其它响应
                    //addRecvMsg(createMsgId(), msg);
                    otherMsgList.Add(new MsgItem(createMsgId(), msg));
                    ack = false;
                    Thread.Sleep(200);
                }
            }
            

            while (isCommRunning() && !ack && counter++ < 10)
            {
                try
                {
                    if (lockLink)
                    {
                        lock (s_spLocker)
                        {
                            msg = spLink.ReadString(1);
                        }
                    }
                    else
                    {
                        msg = spLink.ReadString(1);
                    }

                    if (!string.IsNullOrEmpty(msg))
                    {
                        rst = normalSingleResponse(fc,aName,msg,otherInfo);
                        ack = true;
                        break;
                    }
                    
                }
                catch (nUnCompatibleFrameException cfe)
                {
                    Utility.FileOperate.WriteToLog(cfe.Message);
                    //可能是其它响应
                    //addRecvMsg(createMsgId(), msg);
                    otherMsgList.Add( new MsgItem( createMsgId(), msg) );
                    ack = false;
                    rst = CommResultCode.Exceptions;
                    Thread.Sleep(200);
                }
            }
            if (otherMsgList != null && otherMsgList.Count > 0)
            {
                foreach (MsgItem mi in otherMsgList)
                {
                    addRecvMsg(mi.Id, mi.Msg);
                }
            }

            //if (commError)
            //{
            //    if (OnAxleActionResponse != null)
            //    {
            //        OnAxleActionResponse(Axle.AllAxleName
            //            , AxleCacheManager.getAxle(Axle.AllAxleName)
            //            , AxleActions.Failed
            //            , false
            //            , string.Format("读取到错误帧,请检查通讯链路")
            //        );
            //    }
            //}
            return rst;
        }

        /// <summary>
        /// 获取期望的消息
        /// </summary>
        /// <param name="expPack"></param>
        /// <param name="expContent"></param>
        /// <returns></returns>
        static MsgItem getExpMsg(UnpacketResult expPack, string axleName)
        {
            bool commError = false;
            while (isCommRunning())
            {
                lock (s_msgLocker)
                {
                    MsgItem mItem = getNewMsg();
                    if (mItem != null)
                    {
                        UnpacketResult xpack = Protocol.Unpack(mItem.Msg);
                        if (!xpack.Result)//解释错误说明出现错误帧
                        {
                            rmMsg(mItem.Id);
                            commError = true;
                            break;
                        }
                        expPack.Content = axleName;
                        if (xpack.Approximate(expPack))//回复内容含有期望内容
                        {
                            //得到期望的消息
                            rmMsg(mItem.Id);
                            return mItem;
                        }
                    }
                }
                Thread.Sleep(200);

            }
            if (commError)
            {
                if (OnAxleActionResponse != null)
                {
                    OnAxleActionResponse(Axle.AllAxleName
                        , AxleCacheManager.getAxle(Axle.AllAxleName)
                        , AxleActions.Failed
                        , false
                        , string.Format("读取到错误帧,请检查通讯链路")
                    );
                }
            }
            return null;
        }

        /// <summary>
        /// 获取期望的消息
        /// </summary>
        /// <param name="expPack"></param>
        /// <param name="axleList"></param>
        /// <returns></returns>
        static MsgItem getExpMsg(UnpacketResult expPack, List<string> axleList)
        {

            bool commError = false;
            while (isCommRunning())
            {
                lock (s_msgLocker)
                {
                    MsgItem mItem = getNewMsg();
                    if (mItem != null)
                    {
                        UnpacketResult xpack = Protocol.Unpack(mItem.Msg);
                        if (!xpack.Result)//解释错误说明出现错误帧
                        {
                            rmMsg(mItem.Id);
                            commError = true;
                            break;
                        }
                        foreach (string aName in axleList)
                        {
                            expPack.Content = aName;
                            if (xpack.Approximate(expPack))//回复内容含有期望内容
                            {
                                //得到期望的消息
                                rmMsg(mItem.Id);
                                return mItem;
                            }
                        }
                    }
                }//lock
                Thread.Sleep(200);
            }
            if (commError)
            {
                if (OnAxleActionResponse != null)
                {
                    OnAxleActionResponse(Axle.AllAxleName
                        , AxleCacheManager.getAxle(Axle.AllAxleName)
                        , AxleActions.Failed
                        , false
                        , string.Format("读取到错误帧,请检查通讯链路")
                    );
                }
            }
            return null;
        }


        public static void Process(MsgItem msgItem)
        {
            if (
                msgItem == null 
                || string.IsNullOrEmpty( msgItem.Msg) 
                )
                return;
            //UnpacketResult ur = Protocol.Unpack(msgItem.Msg);
            //ProtocolV2.UnpacketResult ur = ProtocolV2.Unpack(msgItem.Msg);
            //if (
            //    ur.Action ==  AxleActions.RunFinish
            //    || ur.Action == AxleActions.StopFinish
            //    || ur.Action == AxleActions.ToZeroFinish
            //    || ur.Action == AxleActions.RelativeZeroRespond
            //    )
            //{
            //    //procAction(msgItem);
            //    procAction(ur);
            //}//decide is action
            //else
            //{ 
                
            //}
            ProtocolV2.UnpacketResult ur = ProtocolV2.Unpack(msgItem.Msg);
            switch (ur.Action)
            {
                //case AxleActions.ContactRespond: OnContactRespond(ur.Result); break;
                case AxleActions.ParameterSettingRespond: OnPMSettingRespond(ur); break;
                case AxleActions.AccelerationSettingRespond: OnAccelerationSettingRespond(ur); break;
                case AxleActions.RelativeZeroRespond: OnRelativeZeroRespond(ur); break;
                case AxleActions.RunRespond: OnRunRespond(ur); break;
                case AxleActions.StopRespond: OnStopRespond(ur); break;
                case AxleActions.ToZeroRespond: OnToZeroRespond(ur); break;
                case AxleActions.QueryPositionRespond: OnQueryPositionRespond(ur); break;
                case AxleActions.VZeroRespond: OnVZeroRespond(ur); break;




                case AxleActions.RelativeZeroFinish: OnRelativeZeroComplete(ur); break;
                case AxleActions.RunFinish: OnRunComplete(ur); break;
                case AxleActions.StopFinish: OnStopComplete(ur); break;
                case AxleActions.ToZeroFinish: OnToZeroComplete(ur); break;
                case AxleActions.QueryPositionFinish: OnQueryPositionComplete(ur); break;
                case AxleActions.VZeroFinish: OnVZeroComplete(ur); break;


                case AxleActions.VZeroSetFinish: OnVZeroSetComplete(ur); break;
                case AxleActions.VZeroRemoveFinish: OnVZeroRmComplete(ur); break;
                case AxleActions.VZeroFailed: OnVZeroFailedComplete(ur); break;

                case AxleActions.WrongFormat: OnWrongFormat(ur); break;
            }

        }//process function

        static void OnWrongFormat(ProtocolV2.UnpacketResult ur)
        {
            setState("命令格式异常!");
        }

        private static void procAction(MsgItem msgItem)
        {
            AxleAction ax = Protocol.UnpackAction(msgItem.Msg);
            
            if (
                ax != null 
                && ax.AxleList != null
                && ax.AxleList.Count > 0
             )
            {
                foreach (string an in ax.AxleList)
                {
                    //axleName += string.Format("{0}|", an);

                    if (
                        ax.Action == AxleActions.RunFinish
                        || ax.Action == AxleActions.StopFinish
                        )
                    {
                        AxleRunState.Instance[an] = false;
                        if (ax.Result)
                        {
                            AxleManager.QueryPosition(an);
                        }
                    }
                    else if (ax.Action == AxleActions.ToZeroFinish)
                    {
                        ParameterCacheManager.Update(an, Axle.Direction.ForwardDirection, double.MinValue, double.MinValue);
                        int ra = AxleCacheManager.AxleList[an].RunAcceleration;
                        if ( ra != Axle.AccelerationLevel.Constant && ra != Axle.AccelerationLevel.Empty)
                        {
                            AxleManager.AccelerationSetting(an, new Axle.AccelerationLevel(ra));
                        }
                    }

                    if (OnAxleActionResponse != null)
                    {
                        
                        OnAxleActionResponse(an
                                , AxleCacheManager.getAxle(an)
                            , ax.Action
                            , ax.Result
                            , string.Format("[{0}] 轴 {1} : {2}  "
                            , an, ax.Action.ToString(), ax.Result.ToString()
                            )
                        );
                    }
                }
                //string axleName = string.Empty;
                //if (ax.AxleList.Count == 1)
                //{
                //    axleName = ax.AxleList[0];
                //}
                //else
                //{
                    
                //}
                //bool rst = ax.Result;

                //foreach (string an in ax.AxleList)
                //{
                //    QueryPosition(an);
                //}

            }// actions
        }

        private static void procAction(ProtocolV2.UnpacketResult ur)
        {
            string an = ur.AxleName;
            if (
                ur.Action == AxleActions.RunFinish
                || ur.Action == AxleActions.StopFinish
                || ur.Action == AxleActions.RelativeZeroFinish
                            )
            {
                AxleRunState.Instance[an] = false;
                if (ur.Result)
                {
                    if (ur.Action == AxleActions.RelativeZeroFinish)
                    {
                        AxleCacheManager.AxleList[an].RelativeZero = AxleCacheManager.AxleList[an].Position;
                        AxleCacheManager.Update(AxleCacheManager.AxleList[an]);
                    }

                    AxleManager.QueryPosition(an);
                }
            }
            else if (ur.Action == AxleActions.ToZeroFinish)
            {
                ParameterCacheManager.Update(an, Axle.Direction.ForwardDirection, double.MinValue, double.MinValue);
                int ra = AxleCacheManager.AxleList[an].RunAcceleration;
                if (ra != Axle.AccelerationLevel.Constant && ra != Axle.AccelerationLevel.Empty)
                {
                    AxleManager.AccelerationSetting(an, new Axle.AccelerationLevel(ra));
                }
            }

            if (OnAxleActionResponse != null)
            {

                OnAxleActionResponse(an
                        , AxleCacheManager.getAxle(an)
                    , ur.Action
                    , ur.Result
                    , string.Format("[{0}] 轴 {1} : {2}  "
                    , an, ur.Action.ToString(), ur.Result.ToString()
                    )
                );
            }
        }

        private static void procPosition(MsgItem msgItem)
        { 
            
        }

    }
}
